﻿namespace Pe.Petecos.Comercial.Cross.Document.Excel
{
    using System;
    using System.Reflection;
    using System.Collections.Generic;
    using DocumentFormat.OpenXml.Spreadsheet;
    using DocumentFormat.OpenXml.Packaging;
    using System.Linq;
    using DocumentFormat.OpenXml.Wordprocessing;

    /// <summary>
    /// Objeto que representa una fila de Excel
    /// </summary>
    /// <remarks>
    /// Creacion: 	GMD 20140514 <br />
    /// </remarks>
    public class RowData
    {
        /// <summary>
        /// Indice de la fila
        /// </summary>
        public UInt32 RowIndex { get; set; }
        /// <summary>
        /// Inidicador de agrupamiento
        /// </summary>
        public byte OutlineLevel { get; set; }
        /// <summary>
        /// Celdas de la fila
        /// </summary>
        public List<CellData> Cells { get; set; }
        /// <summary>
        /// Estilo por defecto de la fila
        /// </summary>
        public string DefaultStyleId { get; set; }
        /// <summary>
        /// Constructor por Defecto de implementación de la clase.
        /// </summary>
        public RowData() {
            this.Cells = new List<CellData>();
        }
        /// <summary>
        /// Contructor de inicialización de fila con indice
        /// </summary>
        /// <param name="index">Indice de la fila.</param>
        public RowData(UInt32 index)
        {
            this.RowIndex = index;
            this.OutlineLevel = 0;
        }
        /// <summary>
        /// Contructor de inicialización de fila con indice y flag de agrupamiento
        /// </summary>
        /// <param name="index">Indice de la Fila</param>
        /// <param name="outlineLevel">Indicador de agrupamiento</param>
        public RowData(UInt32 index, byte outlineLevel)
        {
            this.RowIndex = index;
            this.OutlineLevel = outlineLevel;
        }
        /// <summary>
        /// Constructor de inicialización de fila 
        /// </summary>
        /// <param name="row">Fila nativa OPEN XML</param>
        /// <param name="sharedStringTable">Tabla compartida de valores OPEN XML</param>
        /// <param name="cellFormats">Formato de celdas OPEN XML</param>
        public RowData(Row row, SharedStringTable sharedStringTable, CellFormats cellFormats)
        {
            this.RowIndex = row.RowIndex;
            this.GetCells(row, sharedStringTable, cellFormats);
        }

        /// <summary>
        /// obtiene las celdas que contiene una fila de excel.
        /// </summary>
        /// <param name="row">objeto Row de OPEN XML -> Fila de donde se obtiene le valor</param>
        /// <param name="sharedStringTable">objeto sharedStringTable de OPEN XML -> contendor de todas los texto del documento</param>
        /// <returns>List : lista de celdas que contiene la fila</returns>
        private void GetCells(Row row, SharedStringTable sharedStringTable, CellFormats cellFormats)
        {
            this.Cells = new List<CellData>();
            var cells = from cell in row.Descendants<Cell>() where cell.CellValue != null select new CellData(cell, sharedStringTable, cellFormats);
            int index = 1;
            foreach (var cell in cells)
            {
                // se compensa la celda en caso este nula
                if (cell.CellIndex != index)
                {
                    while (index < cell.CellIndex)
                    {
                        CellData newCell = new CellData(index, this.RowIndex);
                        this.Cells.Add(newCell);
                        index++;
                    }
                }
                index++;
                this.Cells.Add(cell);
            }
        }
        /// <summary>
        /// Permite el mapeo las celdas de una fila  aun objeto tipado
        /// </summary>
        /// <typeparam name="T">Tipado del Objeto</typeparam>
        /// <param name="obj">Tipo de Objeto</param>
        /// <param name="mapper">Configuración de mapeo</param>
        /// <returns>Intancia nueva del objeto</returns>
        public T MapperRowToObject<T>(Type obj, Dictionary<int, string> mapper)
        {
            if (mapper == null)
            {
                throw new ArgumentException();
            }
            CellData cell;
            var newObj = Activator.CreateInstance(obj);
            for (int i = 0; i < this.Cells.Count; i++)
            {
                cell = this.Cells[i];

            }
            return (T)newObj;
        }
        /// <summary>
        /// Permite setear los valores de las celdas de una fila a partir de un arreglo de datos
        /// </summary>
        /// <param name="values">Valores de las celdas</param>
        public void SetValues(string[] values)
        {
            this.Cells = new List<CellData>();
            CellData cell;
            for (int i = 1; i <= values.Length; i++)
            {
                cell = new CellData(i, this.RowIndex);
                cell.Value = values[i - 1];
                cell.DataType = "System.String";
                if (values[i - 1] != null) { cell.DataType = values[i - 1].GetType().FullName; }
                this.Cells.Add(cell);
            }
        }

        public void SetValues(string[] values, int indexColumn)
        {
            this.Cells = new List<CellData>();
            CellData cell;
            for (int i = 1; i <= values.Length; i++)
            {
                cell = new CellData(i + indexColumn, this.RowIndex);
                cell.Value = values[i - 1];
                cell.DataType = "System.String";
                if (values[i - 1] != null) { cell.DataType = values[i - 1].GetType().FullName; }
                this.Cells.Add(cell);
            }
        }

    }
}
